import { getAnimaLocalStatus } from './anima/animation';

let ignore_data = { data: [] };

const formated = 'formated';

/**
 * 目标视窗 的 top left 位置 及宽高
 * @param {Object} el	--目標元素
 * @return {Object} position	--返回 目标视窗 的 top left 位置 及宽高
 */
function elViewPosition(el) {
  let position = {};

  function getbodyOffsetPosition(el, str) {
    let keys = 'offset' + str[0].toUpperCase() + str.substring(1);
    let translateDire = str == 'top' ? 'translateY' : 'translateX';
    // console.log(keys);
    let num = 0;
    let elclone = el;
    for (; elclone['offsetParent'] != null; ) {
      // console.log(window.getComputedStyle(elclone));
      let matrixstr = window.getComputedStyle(elclone)['transform'];
      if (matrixstr != 'none') {
        let trans = spliteMatrix(matrixstr, translateDire);
        // console.log(trans);
        num += Number(trans);
      }
      // console.log(elclone, elclone['offsetParent']);
      num += Number(elclone[keys]);
      // console.log(num);
      elclone = elclone['offsetParent'];
    }
    return num;
  }

  position['width'] = el.offsetWidth;
  position['height'] = el.offsetHeight;

  position['left'] = getbodyOffsetPosition(el, 'left');
  position['top'] = getbodyOffsetPosition(el, 'top');

  return position;
}

/**
 * 剝離 matrStr 的信息
 * @param {Object} matrStr window.getComputedStyle(el).transform
 * @param {Object} type [scalX,skew,rotate,scalY,translateX,translateY]
 */
function spliteMatrix(matrStr, type) {
  if (!toStringTypeCheck(matrStr, 'string')) {
    console.log('sorry the arguments[0] is not String type');
    return false;
  }
  if (matrStr === 'none') {
    return false;
  }
  //matrix(1, 0, 0, 1, 0, -41.6)
  //matrix\((?<scalX>-?\d+(?:\.\d+)?),\s(?<skew>-?\d+(?:\.\d+)?),\s(?<rotate>-?\d+(?:\.\d+)?),\s(?<scalY>-?\d+(?:\.\d+)?),\s(?<translateX>-?\d+(?:\.\d+)?),\s(?<translateY>-?\d+(?:\.\d+)?)\)
  let resultArr = [];
  let regMatrixStr =
    /matrix\((?<scalX>-?\d+(?:\.\d+)?),\s(?<skew>-?\d+(?:\.\d+)?),\s(?<rotate>-?\d+(?:\.\d+)?),\s(?<scalY>-?\d+(?:\.\d+)?),\s(?<translateX>-?\d+(?:\.\d+)?),\s(?<translateY>-?\d+(?:\.\d+)?)\)/;
  let matchResult = matrStr.match(regMatrixStr);
  if (matchResult.groups) {
    for (let key in matchResult.groups) {
      resultArr[key] = matchResult.groups[key];
    }
    // console.log(resultArr);
    if (type != undefined) {
      if (!toStringTypeCheck(type, 'string')) {
        console.log('sorry the arguments[1] is not String type');
        return false;
      }
      return resultArr[type];
    } else {
      return resultArr;
    }
  }
}

/**
 * @param {styleSheet} styleSheet
 * @param {String} name
 * @param {String} str
 */
function changeKeyframesString(styleSheet, name, str) {
  let NewstyleText = '';
  let result = -1;
  for (let i = 0; i < styleSheet.cssRules.length; i++) {
    if (
      toStringTypeCheck(styleSheet.cssRules[i], 'CSSKeyframesRule') &&
      styleSheet.cssRules[i].name == name
    ) {
      styleSheet.deleteRule(i);
      styleSheet.insertRule(str, i);
      result = i;
    }
    NewstyleText = `${NewstyleText}\n ${styleSheet.cssRules[i].cssText}`;
    // console.log(NewstyleText);
  }
  styleSheet.ownerNode.innerHTML = NewstyleText;
  return result;
}

/**
 * 展示 元素 -- 兩層 setTimeout
 * --目標元素 延迟添加 和 class animation 和 延遲删除
 * @param {Object} el	--目標元素
 * @param {String} animate	-- 動畫class
 * @param {Number} delay	-- 延遲添加 ms
 * @param {Number} lateDrop	-- 延遲刪除 ms (number ||  ['no', 'false', false] (不删除))
 *
 * @return {Number} --延迟添加 和 animation 的時間 和 延遲删除 所用的時間
 */
function endsTimeAnimation(el, animate, delay, lateDrop) {
  //   let classConditionArr = ['disnone'];
  if (!(el instanceof HTMLElement) || animate == undefined) {
    return 0;
  }
  if (getAnimaLocalStatus(el) == true) {
    // if (classConditionArr.indexOf(animate) > -1) {
    //   removeClass(el, animate);
    // }
    removeClass(el, animate);

    // console.log('you got me false condition');
    return 0;
  }
  //返回結果
  let delayResult = 0;

  delay = delay == undefined ? 0 : delay;

  lateDrop =
    lateDrop == undefined
      ? 0
      : ['no', 'false', false].indexOf(lateDrop) > -1
      ? false
      : getNum(lateDrop);
  //   console.log(['no', 'false', false].indexOf(lateDrop), lateDrop);
  //賦值空元素 模擬計算 一次
  if (window.calcdomAnimateDelayEl == undefined) {
    let vac = document.createElement('div');
    vac.classList.add('disnone');
    // vac.innerHTML = '782.24979';
    document.body.appendChild(vac);
    window.calcdomAnimateDelayEl = vac;
  }
  window.calcdomAnimateDelayEl.classList.add(animate);
  let a = window.getComputedStyle(window.calcdomAnimateDelayEl);
  let classDelay = eval(
    parseFloat(a.animationDuration.slice(0, -1)) +
      parseFloat(a.animationDelay.slice(0, -1))
  );
  //   console.log(classDelay);
  //移除 模拟计算的 class
  window.calcdomAnimateDelayEl.classList.remove(animate);
  if (toStringTypeCheck(lateDrop, 'number')) {
    delayResult = Number(delay) + Number(classDelay * 1000) + Number(lateDrop);
  } else {
    delayResult = Number(delay) + Number(classDelay * 1000);
  }

  setTimeout(() => {
    // console.log(el);
    // el.classList.add(animate);
    removeClass(el, animate, true);

    let comedEl = window.getComputedStyle(el);
    // console.log(comedEl);

    //目标 class 延迟时间
    let totalDelay = eval(
      parseFloat(comedEl.animationDuration.slice(0, -1)) +
        parseFloat(comedEl.animationDelay.slice(0, -1))
    );
    // console.log(totalDelay);
    if (toStringTypeCheck(lateDrop, 'number')) {
      setTimeout(() => {
        // el.classList.remove(animate);
        removeClass(el, animate);
      }, Number(delay) + Number(totalDelay * 1000) + Number(lateDrop));
    }
  }, delay);

  return delayResult;
}

/**
 * 建立 唯一 臨時的 style 標簽 到 head
 * @param {String} id -- 設置一個挂載到 window.StaticCss[$1] 的唯一標識
 */
function SetStaticCssTxtFunc(id) {
  window.StaticCss = window.StaticCss
    ? (function () {
        let a = window.StaticCss;
        a['id'].indexOf(id) == -1
          ? (function () {
              a['id'].push(id);
              a[id] = {
                classArr: [],
              };
            })()
          : undefined;
        return a;
      })()
    : (function () {
        let a = {};
        a['id'] = [id];
        a[id] = {
          classArr: [],
        };
        return a;
      })();
  let totalStaticCss = window.StaticCss;

  /**
   *
   * @param {String} cla  -- accurate id String !! == calssName  || id ==static_${className}
   * @param {String} code -- Packaged css animation String !! == innerHtml
   */
  function avanda(cla, code) {
    if (cla == undefined && code == undefined) {
      //返回 縂的 已經定義的 元素
      return claArr;
    }
    // console.log(claArr);
    if (cla == undefined) {
      console.log(
        'sorry we need a id<String> to manage the variable \n plase enter a arguments[0] value'
      );

      return null;
    }

    var hasClaCss = false;
    // console.log("沒進來 ");
    let claArr = totalStaticCss[id];
    // console.log(claArr);

    claArr['classArr'].indexOf(cla) == -1
      ? (function () {
          // console.log("添加")
          claArr['classArr'].push(cla);
          claArr[cla] = code;
        })()
      : (function () {
          hasClaCss = true;
          // console.log("添加過了")

          //cover style code
          let targetStyle = document.getElementById(cla);
          try {
            //for Chrome Firefox Opera Safari
            targetStyle.appendChild(document.createTextNode(code));
          } catch (ex) {
            //for IE
            targetStyle.styleSheet.cssText = code;
          }
        })();

    if (hasClaCss == true) {
      // console.log("you have settled \"" + cla + "\" id CssStyle Now!  In head tag");
      return true;
    }
    if (code != undefined) {
      var style = document.createElement('style');
      style.type = 'text/css';
      style.rel = 'stylesheet';
      try {
        //for Chrome Firefox Opera Safari
        style.appendChild(document.createTextNode(code));
      } catch (ex) {
        //for IE
        style.styleSheet.cssText = code;
      }
      style.setAttribute('class', `static_${cla}`);
      style.setAttribute('id', `${cla}`);

      var head = document.getElementsByTagName('head')[0];
      head.appendChild(style);
    } else if (code == 'remove') {
      if (claArr['classArr'].indexOf(cla) != -1) {
        claArr['classArr'].splice(claArr['classArr'].indexOf(cla), 1);
        // console.log(claArr);
        var claEle = document.getElementById(`${cla}`);
        claEle.remove();
        return `${cla} has been removed`;
      }
      return `${cla} is undefined`;
    } else if (code == undefined) {
      if (claArr['classArr'].indexOf(cla) != -1) {
        //返回 指定的 class
        return claArr['classArr'][cla];
      }
      return `${cla} is undefined`;
    }
  }

  return avanda;
}

/**
 * @param {Object} a --数据对象
 * @param {String} type	--数据类型
 * @return {boolean}
 */
function toStringTypeCheck(a, type) {
  if (type == undefined) {
    return toString.call(a).slice(8, -1).toLowerCase();
  } else if (type.toLowerCase() == 'any') {
    return true;
  }
  // console.log(toString.call(a).slice(8, -1))
  return toString.call(a).slice(8, -1).toLowerCase() == type.toLowerCase();
}

// /**
//  * 输入两个数据 a , b 返回 a + b
//  * @param {Number} a --数字
//  * @param {Number} b --数字
//  */
// function testfunc(a, b) {
// 	return a + b
// }

/**
 * -- 单链查找
 * @param {Object} event	--传递事件 或 元素
 * @param {String} targetString	--目标 元素名称 .abc || #abcd
 *
 * @return {Element} el
 */
function singleLineGetClassEl(event, targetString) {
  let str = [...targetString].slice(1).join('');
  let keyType = targetString[0];

  let el = event.target || event;

  let targetGet = false;

  function parentNodeSearch(event) {
    if (event.parentNode.nodeName == 'BODY') {
      return false;
    }
    if (checkTargetString(event)) {
      el = event.target || event;
      targetGet = true;
      return true;
    }
    parentNodeSearch(event.parentNode);
  }

  function childNodesSearch(event) {
    if (event.childNodes.length > 0) {
      event.childNodes.forEach((currentValue) => {
        if (checkTargetString(currentValue)) {
          el = currentValue.target || currentValue;
          targetGet = true;
          return true;
        }
        childNodesSearch(currentValue);
      });
    }

    return false;
  }

  //查驗 當前 Event 是否為 目標值 返回 boolean
  function checkTargetString(event) {
    //id str
    if (keyType == '#') {
      return event.id != undefined ? event.id == str : false;
    }

    //class str
    if (keyType == '.') {
      return event.classList != undefined
        ? event.classList.contains(str)
        : false;
    }
    return false;
  }

  //向上搜索
  if (!parentNodeSearch(event)) {
    //向下搜索
    childNodesSearch(event);
  }
  console.log(targetGet);
  return el;
}

/**
 * 嵌套 setTimeout 后運行 func 并返回其值
 * @param {number,array} nth --嵌套 setTimeout 的層數<number> / [...delayTime<ms>]
 * @param {function} func -- 待嵌套結束后 返回 運行的 函數值
 */
function settimeNth(nth, func) {
  if (typeof nth == 'number' && nth > 0) {
    return setTimeout(() => {
      settimeNth(--nth, func);
      //   console.log(nth);
    }, 0);
  } else if (toStringTypeCheck(nth, 'array') && nth.length > 0) {
    return setTimeout(() => {
      nth.splice(0, 1);
      settimeNth(nth, func);
      //   console.log(nth);
    }, nth[0]);
  } else {
    return func();
  }
}

/**
 * bool -- !true 默认 删除 classstr
 * bool -- true 添加? 2023.07.29 21:29 星期六 晴雨 3120 分 漂亮 力阳 没有惩罚 ??
 * @param {Element} element
 * @param {String} classstr
 * @param {Boolean} bool --true 尝试 添加 classstr
 */
function removeClass(element, classstr, bool) {
  if (bool == undefined || bool == false) {
    element.classList.contains(classstr)
      ? element.classList.remove(classstr)
      : undefined;
  } else {
    element.classList.contains(classstr)
      ? undefined
      : element.classList.add(classstr);
  }
}

/**
 *用于解析 dom 结构 根据特定关键字 组装 dom 元素
 * 

 * @param {Element} append --元素 挂载位置 直接挂载 (值为 undefined 时 返回 生成的元素 要求只有一个头部节点!!)
 * @param {DomTree} domData --用户自定义 DomT
 * @param {Boolean} boolean -- 确定是否需要 穿插 生成的整体元素 到 childNode 的 前面 (true) 或 后面 (false) || 不需要 设置为 undefined
 * @param {Element} childNode --元素 挂载元素的 某一个子元素
 * @returns {Element}
 * {
	queue: ["a"],
	a: {
		tag: 'details', //-- tag 標簽屬性類型 可以進行自定義
		queue: ["summary", "a_a"], //-- data 屬性一般順序 filter 可以進行干預
		summary: {
			tag: "summary",
			props: ["innerHTML"],
			innerHTML: '飛'
		},
		a_a: {
			tag: 'li',
			props: ["innerHTML", "classlist"],
			innerHTML: '帶你飛',
			classlist: ["neew", "some"]
		}
	}
 */
function domTree(append, domData, boolean, childNode) {
  //dom 序列 queue --按照此序列 进行 dom 次序生成
  //按照 层级 次序 进行 组装 dom

  //dom 标签 tag -- 生成的 dom 元素类型
  //dom 属性 props -- 一般 按照 el[props[i]]=node[props[i]]
  return queueDom(append, domData, boolean, childNode);

  /**
   * @param {Object} nod	-- 当前 组装根节点
   * @param {Object} info	-- 当前 节点信息
   * 次序 dom 节点 并 组装到 当前 nod 节点上
   */
  function queueDom(nod, info, boolean, childNode) {
    if (info == undefined || info['queue'] == undefined) {
      return undefined;
    }
    for (let i of info['queue']) {
      // console.log("進入節點循環");
      let currentDom = growthDom(info[i]);
      if (nod == undefined) {
        nod = currentDom;
      } else {
        if (boolean != undefined) {
          if (boolean == true) {
            nod.insertBefore(currentDom, childNode);
          } else {
            if (childNode.nextelementsibling != null) {
              nod.insertBefore(currentDom, childNode.nextelementsibling);
            } else {
              nod.appendChild(currentDom, childNode);
            }
          }
        } else {
          //裝載 當前 匹配好的節點
          nod.appendChild(currentDom);
        }
      }

      //如果 此時 當前節點 有子節點
      if (info[i]['queue'] != undefined) {
        // console.log("進入子節點循環");
        queueDom(currentDom, info[i]);
      }
    }
    return nod;
  }

  /**
   * @param {Object} info	-- 当前 节点信息
   * 生成 dom 元素 并 赋值 其相关属性
   */
  function growthDom(info) {
    let el;
    if (info['tag'] != undefined) {
      // createElement -- 依据 tag 创建 element
      el = document.createElement(info['tag']);
    }
    if (info['props'] != undefined && typeof el.nodeName === 'string') {
      //装填属性
      for (let k of info['props']) {
        // console.log(el, k, info[k]);
        //添加 class
        if (['classList', 'class', 'classlist'].indexOf(k) > -1) {
          el.classList.add(...info[k]);
        }
        // else if(["id"].indexOf(k)>-1){
        // 	el.id=info[k]
        // }
        else {
          el[k] = info[k];
        }
      }
    }
    if (info['attribute'] != undefined && typeof el.nodeName === 'string') {
      for (let k of info['attribute']) {
        el.setAttribute(k, info[k]);
      }
    }
    if (info['events'] != undefined && typeof el.nodeName === 'string') {
      for (let k of info['events']) {
        el.addEventListener(k, info[k]);
      }
    }
    return el;
  }
}

/**
 * 反转 动画 reverse  css Animation
 * @param {Object} styleEl -- 自定義 style
 */
function rebackAnimation(styleEl) {
  //匹配 % | from to 字段名 和 `{[^}]*?}` 最小字段數據
  //groups 字段 -- num | from | to | keyframe
  let REkeyframesGroups =
    /(?:(?<num>[^{]{1,5})%|(?<from>from)|(?<to>to)) (?<keyframe>\{[^}]*?\})/g;

  //簡單 trim 一下 方便 匹配 字段
  let trimKeyframes = '';
  let tietu = '';
  for (var i = 0; i < styleEl.sheet.cssRules.length; i++) {
    tietu += styleEl.sheet.cssRules[i].cssText + '\n';

    if (toStringTypeCheck(styleEl.sheet.cssRules[i], 'CSSKeyframesRule')) {
      trimKeyframes = styleEl.sheet.cssRules[i].cssText;
      if (styleEl.sheet.cssRules[i].cssRules.length == 2) {
        trimKeyframes = trimKeyframes.replace('0%', 'from');
        trimKeyframes = trimKeyframes.replace('100%', 'to');
      }
    }
  }
  tietu.slice(-1, 1);
  console.log(tietu);
  styleEl.innerHTML = tietu;

  //記錄原始數據的 對象 --data 調取 索引對象key
  let loopArr = {
    data: [],
  };

  //每次 循環 的匹配值
  let regResult;

  //反轉 loopArr
  let reLoopArr = {
    data: [],
  };

  //REloop 補齊字段
  let joinstr = '';

  do {
    //獲取 匹配字段
    regResult = REkeyframesGroups.exec(trimKeyframes);
    console.log(regResult);

    if (regResult != null) {
      //提取 groups
      let reGroups = regResult.groups;

      switch (true) {
        //提取 from 信息
        case reGroups['from'] != undefined:
          // console.log("from");
          //放入 from key
          loopArr['data'].push('from');
          loopArr['from'] = reGroups.keyframe;

          break;

        //提取 to 信息
        case reGroups['to'] != undefined:
          // console.log("to");
          //放入 to key
          loopArr['data'].push('to');
          loopArr['to'] = reGroups.keyframe;
          break;

        //提取 name 信息
        case reGroups['num'] != undefined:
          // console.log("num", reGroups["num"]);
          //放入 num key
          loopArr['data'].push(reGroups.num);
          loopArr[reGroups.num] = reGroups.keyframe;
          break;
      }
    }
  } while (regResult != null);

  console.log(loopArr);

  function reKeyframe() {
    let reKeyframeBody = /@keyframes [^{]*? \{(?<changeField>[^]*)\}/;
    for (let i = 0; i < loopArr['data'].length; i++) {
      if (loopArr['data'][i] == 'from') {
        reLoopArr['data'].push('to');
        reLoopArr['to'] = loopArr[loopArr['data'][i]];
      } else if (loopArr['data'][i] == 'to') {
        reLoopArr['data'].push('from');
        reLoopArr['from'] = loopArr[loopArr['data'][i]];
      } else if (Number(loopArr['data'][i]) <= 100) {
        let reNumber = 100 - Number(loopArr['data'][i]);
        let keyaframe =
          (reNumber | 0) === reNumber ? reNumber : reNumber.toFixed(2);
        reLoopArr['data'].push(keyaframe);
        reLoopArr[keyaframe] = loopArr[loopArr['data'][i]];
      }
    }

    //補齊 字段
    if (reLoopArr['from'] != undefined) {
      joinstr += `\n\tfrom ${reLoopArr['from']}\n\tto ${reLoopArr['to']}`;
    } else {
      //重排序 默認 遞增排序
      reLoopArr['data'].sort((a, b) => a - b);
      console.log(reLoopArr['data']);

      for (let i = 0; i < reLoopArr['data'].length; i++) {
        //添加 補齊 字段
        joinstr += `\n\t${reLoopArr['data'][i]}% ${
          reLoopArr[reLoopArr['data'][i]]
        }`;
      }
      joinstr += '\n';
    }

    console.log(joinstr);

    let rekeyBody = reKeyframeBody.exec(trimKeyframes);
    console.log(rekeyBody);

    if (rekeyBody != null) {
      let rekeyBodyGs = rekeyBody.groups;
      console.log(rekeyBodyGs['changeField']);
      console.log(trimKeyframes);
      let rekeyframed = trimKeyframes.replace(
        rekeyBodyGs['changeField'],
        joinstr
      );
      //綁定 style 到 標簽
      // (不是自動綁定 可以進行數據的監聽) :(
      console.log(rekeyframed);
      styleEl.innerHTML = styleEl.innerHTML.replace(trimKeyframes, rekeyframed);
      return rekeyframed;
    }
  }

  return reKeyframe();
}

/**
 * 返回 含数字开头字符串的开头 数字
 * @param {String} str 含数字开头的字符串
 * @returns {Number}
 */
function getNum(str) {
  // console.log(str);
  let regNumStr = /(?<number>\d+(?:\.\d+)?)\D*/;
  // let a = Number(regNumStr.exec(str)['groups']['number']);
  // console.log(a);
  // return a;
  return Number(regNumStr.exec(str)['groups']['number']);
}

/**
 * 挂载 唯一元素 并绑定 值对象
 * @param {Object|Array} objSource 目标挂载元素
 * @param {String} key 新挂载名称
 * @param {Object} obj 新 挂载 名称 的 值 对象
 * @param {String} data 挂载预定位置 默认为 "data" 需要 该预设位置为 数组
 * @returns
 */
function ObjectOnlyPushSet(objSource, key, obj, data) {
  if (data != undefined) {
    if (objSource[data] == undefined) {
      //   console.log(`sorry your ${data} is not a available prop`);
      return false;
    }
    if (objSource[data].indexOf(key) == -1) {
      objSource[data].push(key);
      if (obj != undefined) {
        objSource[key] = obj;
      }
      return true;
    }
    // console.log(`sorry your key:${key} is aready in your Object[${data}]`);
    return false;
  } else if (toStringTypeCheck(objSource['data'], 'array')) {
    if (objSource['data'].indexOf(key) == -1) {
      objSource['data'].push(key);
      if (obj != undefined) {
        objSource[key] = obj;
      }
      return true;
    }
    // console.log(`sorry your key:${key} is aready in your Object["data"]`);

    return false;
  } else {
    if (toStringTypeCheck(objSource, 'array')) {
      if (objSource.indexOf(key) == -1) {
        objSource.push(key);
      }
      return true;
    }
    // console.log(`sorry your key:${key} is aready in your Array`);

    return false;
  }
}

/**
 * 尝试禁用 当前指定函数中的 部分 log 输出
 * @param {String} funcName 当前使用函数的域 || undefine 所有 使用该函数的
 * @param {String} str 日志 或者 "ignore"||"open" (开关控制 当前函数 是否启用 日志输出) || undefine 当前函数的 输出状态
 * @returns
 */
function clog_i(funcName, str) {
  //忽视 当前函数下的 所有 log 日志
  if (funcName == undefined) {
    console.log(ignore_data);
    return;
  } else if (str == 'ignore') {
    console.log(funcName + ' log will ignore!');
    ObjectOnlyPushSet(ignore_data, funcName, 'ignore');
  } else if (str == 'open') {
    console.log(funcName + ' log will open!');
    ObjectOnlyPushSet(ignore_data, funcName, 'open');
  } else if (str == undefined) {
    let io = `${
      ignore_data[funcName] == undefined
        ? 'open'
        : ignore_data[funcName] == 'open'
        ? 'open'
        : 'ignore'
    }`;
    console.log(funcName + ' log is' + io);
  } else {
    console.log(str);
  }
}

/**
 * 根据 imp 信息
 *
 * reflash -- 启用 热更新
 *
 * reflashFunc -- reflashFunc(imp[data][i]) 返回 认定 数据
 *
 * retainField -- 函数(自运行 无参数) 数组 字符串 统一返回 数组 进行 模式 判定
 *
 * 模式内 取消信息 检索
 *
 * @param {Object} ImpactObj impact Object 给定冲积平原对象
 * @param {Boolean} reflash 是否热更新
 * @param {Function|undefined} reflashFunc 根据 imp[data][i] 数据 进行 数据获取 返回值 为 undefined 时 默认为 获取以imp[data][i] 数据 为 ID 的 dom 节点
 * @param {array} retainField 保留字段 可以是 函数(自运行 无参数) 数组 字符串 统一返回 数组
 * @returns
 */
function getReflashImp(ImpactObj, reflash, reflashFunc, retainField) {
  if (reflash) {
    let el_i;
    let retainArr;
    if (toStringTypeCheck(retainField, 'function')) {
      retainArr = retainField();
    }
    if (toStringTypeCheck(retainField, 'array')) {
      retainArr = retainField;
    }
    if (toStringTypeCheck(retainField, 'string')) {
      retainArr = [retainField];
    }
    for (let i = 0; i < ImpactObj['data'].length; i++) {
      if (retainArr.indexOf(ImpactObj['data'][i]) > -1) {
        continue;
      }
      if (reflashFunc == undefined) {
        el_i = document.getElementById(ImpactObj['data'][i]);
      } else {
        el_i = reflashFunc(ImpactObj['data'][i]);
      }

      // 如果当前元素 还存在
      if (el_i != undefined) {
        continue;
      }
      // 删除 未有 元素 的 吸附作用域
      delete ImpactObj[ImpactObj['data'][i]];
      ImpactObj['data'].splice(i, 1);
    }
  }
  return ImpactObj;
}

/**
 * 捕获数组
 * -
 * 根据传入参数 模拟获取 其中所指定的 数组
 * @param {any} par
 * @param {Array} a 函数 参数填充 === par(a0,a1,a2)
 * @return {Array} 返回 数组对象
 */
function CaptureArray(par, ...a) {
  //   console.log(par);
  if (toStringTypeCheck(par, 'array')) {
    if (a == undefined) {
      return par;
    }
    for (let i = 0; i < a.length; i++) {
      /**
       * 解构 拼接 字符串 数据
       */
      if (toStringTypeCheck(a[i], 'string')) {
        par.push(a[i]);
      } else if (toStringTypeCheck(a[i], 'array')) {
        /**
         * 解构 拼接 数组
         */
        par.push(...a[i]);
      } else if (toStringTypeCheck(a[i], 'function')) {
        /**
         * 捕获 函数后 进行 拼接 数组
         */
        par.push(...CaptureArray(a[i]));
      }
    }
    return par;
  }
  if (toStringTypeCheck(par, 'function')) {
    if (a == undefined) {
      return CaptureArray(par());
    }
    return CaptureArray(par(...a));
  }
  if (toStringTypeCheck(par, 'string')) {
    if (a == undefined) {
      return [par];
    }
    return [par, ...a];
  }
}

/**
 * enum 对象
 * -
 * 将对象 proxy 设置成 enum 对象
 * @param {Object} obj 对象 proxy 监听 设置成 固定的 enum 模式
 * @returns
 */
function Enum(obj) {
  return new Proxy(obj, {
    get(_, prop) {
      if (Object.prototype.hasOwnProperty.call(obj, prop)) {
        return obj[prop];
      }
      return undefined;
    },
    set(_, prop, value) {
      console.log(
        'you are trying to change Enum Prop' + prop + ' Value : ' + value
      );
    },
  });
}

/**
 * empty 复制对象 克隆对象
 * -
 * @param {any} o 复制对象 简单复制对象 的 属性 不包括其特质 类含义
 * @returns {any} 返回 全新的 简单复制对象
 */
function emptyClone(o) {
  let curo;
  if (toStringTypeCheck(o, 'function')) {
    curo = o;
  } else if (toStringTypeCheck(o, 'string')) {
    curo = o;
  } else if (toStringTypeCheck(o, 'number')) {
    curo = o;
  } else if (toStringTypeCheck(o, 'boolean')) {
    curo = o;
  } else if (toStringTypeCheck(o, 'array')) {
    curo = [];
    for (let i = 0; i < o.length; i++) {
      curo.push(emptyClone(o[i]));
    }
  } else if (o instanceof Object) {
    curo = {};
    for (const key in o) {
      if (Object.hasOwnProperty.call(o, key)) {
        curo[key] = emptyClone(o[key]);
      }
    }
  } else {
    curo = o;
  }
  return curo;
}

/**
 * 格式化一个数据 
 * -
 * 可以 采用 [函数,默认值,格式对象的信息] 填充属性
 * 
 * --formated 标识符 true 代表 该 对象进行过 格式化
 * @param {Object} formatProp format 信息 对象
 * @param {Object|String} keyVal_o 需要 格式的对象
 * @param {String} data 当 keyVal_o 为 单一值(非 object 对象) 挂载预定位置 默认为 "value"
 * @example 
 * let fromat_o = {
  prop_o: [
    '663',
    function () {
      return this.value;
    },
  ],
  infStatus: function () {
    return this.kel;
  },
  jkl: '666',
};
let fora1 = '778';
let fora2 = { value: '789' };
console.log(formatObj(fromat_o, fora1));    --{prop_o: '778', infStatus: undefined, jkl: '666', formated:true}
console.log(formatObj(fromat_o, fora2));    --{prop_o: '789', infStatus: undefined, jkl: '666', formated:true}
console.log(formatObj(fromat_o, {}));       --{prop_o: '663', infStatus: undefined, jkl: '666', formated:true}
 */
function formatObj(formatProp, keyVal_o, data) {
  // 设置 value 默认值
  data == undefined ? (data = 'value') : undefined;
  let a = {};

  if (toStringTypeCheck(keyVal_o, 'object')) {
    if (formatProp['data'] != undefined) {
      let key;
      for (let i = 0; i < formatProp['data'].length; i++) {
        key = formatProp['data'][i];
        funck(key);
      }
    } else {
      for (const key in formatProp) {
        if (Object.hasOwnProperty.call(formatProp, key)) {
          funck(key);
        }
      }
    }
  } else if (toStringTypeCheck(keyVal_o, 'string')) {
    a[data] = keyVal_o;
    a = formatObj(formatProp, a, data);
  } else if (toStringTypeCheck(keyVal_o, 'function')) {
    a[data] = keyVal_o;
    a = formatObj(formatProp, a, data);
  } else if (toStringTypeCheck(keyVal_o, 'array')) {
    a[data] = keyVal_o;
    a = formatObj(formatProp, a, data);
  }
  a[formated] = true;

  function funck(key) {
    if (toStringTypeCheck(formatProp[key], 'array')) {
      if (toStringTypeCheck(formatProp[key][1], 'function')) {
        a[key] = formatProp[key][1].call(keyVal_o);
      }
      if (a[key] == undefined) {
        a[key] = formatProp[key][0];
      }
    } else if (toStringTypeCheck(formatProp[key], 'function')) {
      a[key] = formatProp[key].call(keyVal_o);
    } else {
      a[key] = formatProp[key];
    }
  }

  return a;
}

/**
 * 回溯 记录 关键字
 */
let historyObj = '_h';
/**
 * 回溯 记录 顶峰值
 */
let historyMaxNum = 100;

/**
 * 回溯 记录
 * -
 * 记录 {data:[]} 这种 数据 类型的 值 覆盖 记录 并且 可以 返回 某个值
 *
 * @param {this} that object {data:[]} 这种数据 类型
 * @param {String} key prop 值
 * @param {object} val 数据 值
 */
function rebackSetObj(that, key, val) {
  if (that[historyObj] == undefined) {
    that[historyObj] = { data: [] };
    that[rebakProp] = rebakProp;
  }
  if (!ObjectOnlyPushSet(that, key, val)) {
    histtorySetOnj(that, key, that[key]);
    that[key] = val;
  }
}

/**
 * 历史属性记录
 * -
 * 向 {data:[]} 对象 添加 一个 历史 属性 记录
 * @param {this} that {data:[]} 对象
 * @param {String} key prop 属性
 * @param {Object} val 上一个 历史值
 */
function histtorySetOnj(that, key, val) {
  //首次 直接添加
  if (ObjectOnlyPushSet(that[historyObj], key, { key: [0], 0: [val] })) {
    return;
  }

  for (let i = 1; i < historyMaxNum; i++) {
    if (ObjectOnlyPushSet(that[historyObj][key], i, val, key)) {
      return;
    }
  }
}

/**
 * 调取 交换 指定的 覆盖赋值
 * -
 * @param {String} key prop 属性 名称
 * @param {Number} nth 正负 取值 -1 上一次 改变 1 最开始 改变的值
 */
function rebakProp(key, nth) {
  if (nth == undefined) {
    rebakProp(key, -1);
  }
  let currVal = this[key];
  if (nth < 0) {
    nth = this[historyObj][key][key].length - 1 + nth;
  }
  // 预防 获取 超出阀值 取值
  if (nth >= this[historyObj][key][key].length) {
    nth = this[historyObj][key][key].length - 1;
  }

  let hisVal = this[historyObj][key][nth];
  // 交换信息
  [this[key], this[historyObj][key][nth]] = [hisVal, currVal];
  //   console.log(
  //     'rebacked val:',
  //     this[key],
  //     'historyVal:',
  //     this[historyObj][key][nth],
  //     'hisval:',
  //     hisVal,
  //     'currVal',
  //     currVal
  //   );
}

export {
  elViewPosition,
  spliteMatrix,
  changeKeyframesString,
  endsTimeAnimation,
  SetStaticCssTxtFunc,
  toStringTypeCheck,
  singleLineGetClassEl,
  settimeNth,
  removeClass,
  domTree,
  rebackAnimation,
  // testfunc
  getNum,
  ObjectOnlyPushSet,
  clog_i,
  getReflashImp,
  CaptureArray,
  Enum,
  emptyClone,
  formatObj,
  rebackSetObj,
};
